package com.lyeducation.util.jwt;

import com.lyeducation.redis.RedisUtil;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;

@Component
public final class JwtUtil {
  @Autowired
  private RedisUtil redisUtil;
  //  @Autowired private RedisTemplate redisTemplate;
  @Autowired private JwttokenconfigBean jwttokenconfigBean;

  public String getJwtTokenByRequestHeader(HttpServletRequest request) {
    String jwtToken = null;
    String authHeader = request.getHeader(this.getJwttokenconfigBean().getHeader());
    if (authHeader != null && authHeader.startsWith(this.getJwttokenconfigBean().getTokenHead())) {
      // 通过token自带的信息生成登录实体username password roles
      // 如果验证token如果成功则存入SecurityContextHolder上下文供后面url资源权限认证
      jwtToken = authHeader.substring(this.getJwttokenconfigBean().getTokenHead().length());
    }
    return jwtToken;
  }

  public void addJwtTokenToRedisHash(String jwtJti, String jwtToken) {
    Object[] o = new Object[2];
    o[0] = jwtToken;
    o[1] = System.currentTimeMillis() + jwttokenconfigBean.getRefreshToken();
    redisUtil.hset(JwttokenconfigEnum.jwtTokenHash.getValue(), jwtJti, o);
//    redisTemplate.opsForHash().put(JwttokenconfigEnum.jwtTokenHash.getValue(), jwtJti, o);

    // redisTemplate.expire只对顶级key起作用，不对具体的某个集合的某个属性key起作用
    //
    // redisTemplate.expire(JwttokenconfigEnum.jwtTokenHash.getValue(),jwttokenconfigBean.getEffectiveTime(),TimeUnit.MILLISECONDS);
  }

  public boolean isHasJwtTokenByRedisHash(String jwtJti) {
    return redisUtil.hHasKey(JwttokenconfigEnum.jwtTokenHash.getValue(), jwtJti);
//    return redisTemplate.opsForHash().hasKey(JwttokenconfigEnum.jwtTokenHash.getValue(), jwtJti);
  }

  public Object[] getJwtTokenArrayByRedisHash(String jwtJti) {
//    Object jwtTokenArrayObj =
//        redisTemplate.opsForHash().get(JwttokenconfigEnum.jwtTokenHash.getValue(), jwtJti);

    Object jwtTokenArrayObj =
            redisUtil.hget(JwttokenconfigEnum.jwtTokenHash.getValue(), jwtJti);
    if (jwtTokenArrayObj != null) {
      Object[] resJwtTokenArray = (Object[]) jwtTokenArrayObj;
      return resJwtTokenArray;
    }
    return null;
  }

  public boolean removeJwtTokenByRedisHash(String jwtJti) {
    boolean res = true;
    long number =
            redisUtil.hdel(JwttokenconfigEnum.jwtTokenHash.getValue(), jwtJti);
//    long number =
//        redisTemplate.opsForHash().delete(JwttokenconfigEnum.jwtTokenHash.getValue(), jwtJti);
    if (number != 1) {
      res = false;
    }

    return res;
  }

  // you can put any data in the map
  public String generateToken(Map<String, Object> paramMap) {
    // 1000 hour
    // 签发时间
    Date iat = Calendar.getInstance().getTime();

    long effectiveTime = jwttokenconfigBean.getEffectiveTime();

    long expLong = iat.getTime() + effectiveTime;

    // 过期时间
    Date exp = new Date(expLong);
    paramMap.put(JwttokenconfigEnum.createDate.getValue(), iat.getTime());
    String jwt =
        Jwts.builder()
            .setHeaderParam(JwttokenconfigEnum.type.getValue(), JwttokenconfigEnum.JWT.getValue())
            .setClaims(paramMap)
            .setIssuedAt(iat)
            .setExpiration(exp)
            .setNotBefore(iat)
            .setIssuer(jwttokenconfigBean.getIss())
            .signWith(SignatureAlgorithm.HS512, jwttokenconfigBean.getBase64Secret())
            .compact();
    return jwt;
  }

  /**
   * 解析token时间是去从毫秒为单位变为以秒为单位
   *
   * @param token
   * @return
   */
  public Map<String, Object> validateToken(String token) {
    Map<String, Object> body =
        Jwts.parser()
            .setSigningKey(jwttokenconfigBean.getBase64Secret())
            .parseClaimsJws(token)
            .getBody();
    return body;
  }

  /**
   * 自定义createDate能获取到当前的创建时间 利用exp过期时间-iat签发时间得到有效期时间+自定义createDate<当前时间则过期 如果大于
   * 则是否大于20,再过20秒就过期是的话刷新towken
   *
   * @param map 验证后的towkenMap
   * @return 改为每次请求都刷新token可防止重复请求
   */
  public String refreshToken(Map map) {
    if (jwttokenconfigBean.isEveryRequestRefreshToken()) {
      return generateToken(map);
    }
    long createDateLong =
            Long.parseLong(map.get(JwttokenconfigEnum.createDate.getValue()).toString());
//    log.info("refreshToke创建时间：" + createDateLong);
    long nowTime = System.currentTimeMillis();
    long timeLeft = jwttokenconfigBean.getEffectiveTime() + createDateLong - nowTime;
//        log.info("jwtToken 剩余刷新时间timeLeft：" + timeLeft);
//        如果验证通过的情况下
    if (timeLeft < jwttokenconfigBean.getRefreshTime() && timeLeft > 0) {
      return generateToken(map);
    }
    return null;
  }

  public JwttokenconfigBean getJwttokenconfigBean() {
    return jwttokenconfigBean;
  }
}
